// https://www.luogu.com.cn/problem/P2819

#include <iostream>
using namespace std;

int n, k, m;            // n:顶点数, k:边数, m:颜色数
int graph[105][105];    // 邻接矩阵存储图，graph[i][j]=1表示顶点i和j之间有边
int color[105];         // 记录每个顶点的颜色，color[i]表示顶点i的颜色(0表示未着色)
int ans = 0;            // 记录合法的着色方案总数

/**
 * 检查给顶点u涂颜色c是否合法
 * @param u 要检查的顶点编号
 * @param c 要检查的颜色
 * @return 如果颜色c对于顶点u合法返回true，否则返回false
 */
bool valid(const int u, const int c) {
    // 遍历所有顶点，检查与u相邻的顶点
    for (int v = 1; v <= n; v++) {
        // 如果顶点u和v之间有边，且顶点v已经涂了颜色c
        if (graph[u][v] && color[v] == c) {
            return false;
        }
    }
    return true;
}

/**
 * 深度优先搜索函数，递归地为顶点着色
 * @param u 当前要着色的顶点编号
 */
void dfs(const int u) {
    if (u > n) {
        ans++;
        return;
    }

    // 尝试为当前顶点u涂上第1到第m种颜色
    for (int c = 1; c <= m; c++) {
        if (valid(u, c)) {
            color[u] = c;   // 给顶点u涂上颜色c
            dfs(u + 1);     // 递归处理下一个顶点
            color[u] = 0;   // 回溯：撤销顶点u的颜色，尝试下一种颜色
        }
    }
}

int main() {
    scanf("%d%d%d", &n, &k, &m);
    int a, b;
    for (int i = 0; i < k; i++) {
        scanf("%d%d", &a, &b);
        // 在邻接矩阵中记录边（无向图，所以两个方向都要记录）
        graph[a][b] = 1;
        graph[b][a] = 1;
    }

    // 从第1个顶点开始深度优先搜索
    dfs(1);
    printf("%d\n", ans);
    return 0;
}